package com.wsm.util.httpclient.filter;

import com.wsm.util.httpclient.annotation.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.filter.AbstractClassTestingTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Modifier;

/**
 * @author ：wangshimin
 * @date ：Created in 2021-02-27 下午 02:03
 * @description：
 * @version:
 */
public class RequestTypeFilter extends AbstractClassTestingTypeFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequestTypeFilter.class);

    @Override
    protected boolean match(ClassMetadata metadata) {
        Class<?> clazz = transformToClass(metadata.getClassName());
        if (clazz == null || !clazz.isAnnotationPresent(Request.class)) {
            return false;
        }
        if (isAnnotatedBySpring(clazz)) {
            throw new IllegalStateException("HttpClient-util: class {" + clazz.getName() + "} is already spring bean");
        }
        return checkClazz(clazz);
    }

    private boolean checkClazz(Class<?> clazz) {
        //过滤非抽象类非接口,注解枚举,内部类及匿名类
        return (clazz.isInterface() && Modifier.isAbstract(clazz.getModifiers()))
                && !(clazz.isAnnotation() || clazz.isEnum() || clazz.isMemberClass() || clazz.getName().contains("$"));
    }

    /**
     * @param className
     * @return Class
     */
    private Class<?> transformToClass(String className) {
        Class<?> clazz = null;
        try {
            clazz = ClassUtils.forName(className, this.getClass().getClassLoader());
        } catch (ClassNotFoundException e) {
            LOGGER.info("HttpClient-util:{},The specified httpUtil base class was not found", className);
        }
        return clazz;
    }

    /**
     * @param clazz
     * @return boolean
     */
    private boolean isAnnotatedBySpring(Class<?> clazz) {
        return clazz.isAnnotationPresent(Service.class) || clazz.isAnnotationPresent(Component.class)
                || clazz.isAnnotationPresent(Repository.class) || clazz.isAnnotationPresent(Controller.class);
    }

}